import csv
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import plotly.express as px
import plotly.graph_objects as go
from cpmm import CPMM, run_experiment
Market goes from 1:1 odds to 3:1 odds for YES (much more people bet on NO). Fee is 2%. How much turnover to break even? In the example below LP needs a turnover (stake from betters) to be ~22x initial liquidity to break even
cpmm = CPMM(fee_fraction=0.02)
initial_liquidity = 1000
amount = 10
cpmm.create_event(initial_liquidity, initial_yes_to_no=1)
vals = []
yes_total_payout = 0
for i in range(1, 1001):
yes_payout = cpmm.buy_token(1, amount)[1]
cpmm.buy_token(0, amount * 3)
yes_total_payout += yes_payout
yes_odds = cpmm.calc_british_odds(yes_payout, amount)
vals.append([yes_payout,
yes_odds,
cpmm.lp_token / cpmm.liquidity,
yes_total_payout,
cpmm.fee_pool / cpmm.liquidity,
cpmm.calc_impermanent_loss() / cpmm.liquidity,
cpmm.calc_outstanding_token()[1]])
df = pd.DataFrame(data=vals, columns=["yes payout", "yes odds", "total stake", "yes total reward", "fee pool", "impermanent loss", "outstanding token"])
fig_1 = px.line(df, x="total stake", y=["fee pool", "impermanent loss"], title='fees and loss vs total stake. all values are represented as % of initial liquidity including the stake')
display(fig_1)
fig_2 = px.line(df, x="yes odds", y=["fee pool", "impermanent loss"], title='fees and loss vs odds. all values are represented as % of initial liquidity')
fig_2.update_yaxes(ticksuffix=":1")
display(fig_2)
display(df)
| yes payout | yes odds | total stake | yes total reward | fee pool | impermanent loss | outstanding token | |
|---|---|---|---|---|---|---|---|
| 0 | 19.504892 | 0.950489 | 1.0392 | 19.504892 | 0.0008 | 0.019315 | 39.009811 |
| 1 | 19.889006 | 0.988901 | 1.0784 | 39.393898 | 0.0016 | 0.037542 | 76.547847 |
| 2 | 20.272793 | 1.027279 | 1.1176 | 59.666691 | 0.0024 | 0.054761 | 112.694141 |
| 3 | 20.655834 | 1.065583 | 1.1568 | 80.322525 | 0.0032 | 0.071044 | 147.521669 |
| 4 | 21.037725 | 1.103772 | 1.1960 | 101.360250 | 0.0040 | 0.086457 | 181.097190 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 995 | 39.200000 | 2.920000 | 40.0432 | 38296.386814 | 0.7968 | 0.427529 | 1174.342124 |
| 996 | 39.200000 | 2.920000 | 40.0824 | 38335.586814 | 0.7976 | 0.427529 | 1174.342124 |
| 997 | 39.200000 | 2.920000 | 40.1216 | 38374.786814 | 0.7984 | 0.427529 | 1174.342124 |
| 998 | 39.200000 | 2.920000 | 40.1608 | 38413.986814 | 0.7992 | 0.427529 | 1174.342124 |
| 999 | 39.200000 | 2.920000 | 40.2000 | 38453.186814 | 0.8000 | 0.427529 | 1174.342124 |
1000 rows × 7 columns
Shows loss (more red) and profit (more green) made by LP as a function of total stake (how much was staked by betters) vs. odds divergence (how much betters shifted market from initial liquidity provision. example: LP thinks Trump:Biden is 1:1. better think that Trump:Biden is 3:1 and bet more against Trump)
summary of results below
TODO: if we increase fees then LP can risk more liquidity and we decrease slippage. model what is more efficient
# Y axis - shift the odds, X axis turnover as % of liquidity, COLOR - profit/loss scaled as fraction of liquidity
def run_market(initial_liquidity, fee_fraction, max_turnover_fraction, max_yes_odds, max_slippage, fee_to_liquidity_fraction) -> CPMM:
cpmm = CPMM(fee_fraction=fee_fraction, fee_to_liquidity_fraction=fee_to_liquidity_fraction)
amount = initial_liquidity * max_slippage
no_amount = amount * max_yes_odds
cpmm.create_event(initial_liquidity)
# how many steps, each steps puts amount for YES and amount * odds into no
turnover_steps = (max_turnover_fraction * initial_liquidity) // (amount + no_amount) + 1
# vals = []
for i in range(1, int(turnover_steps)):
cpmm.buy_token(1, amount)
cpmm.buy_token(0, no_amount)
return cpmm
# cpmm = run_market(1000, 0.02, 400, 8, 0.02)
# # cpmm.calc_impermanent_loss()
# df = cpmm.history_as_dataframe
# df["odds"] = (df["returned tokens"] - df["amount"]) / df["amount"]
# display(df)
def run_map(initial_liquidity, fee_fraction, max_turnover_fraction, max_yes_odds, max_slippage, fee_to_liquidity_fraction=0):
profit_mx = []
x_labels = np.arange(0.2, max_turnover_fraction, max_turnover_fraction / 250.0)
y_labels = np.arange(1, max_yes_odds, 0.2)
for max_yes_odds in y_labels:
vals = []
for max_turnover_fraction in x_labels:
cpmm = run_market(initial_liquidity, fee_fraction, max_turnover_fraction, max_yes_odds, max_slippage, fee_to_liquidity_fraction)
profit = cpmm.fee_pool - cpmm.calc_impermanent_loss()
vals.append(profit)
profit_mx.append(vals)
return profit_mx, x_labels, y_labels
def run_scatter(initial_liquidity, fee_fraction, max_turnover_fraction, max_yes_odds, max_slippage, fee_to_liquidity_fraction=0):
profit_mx = []
x_labels = np.arange(0.2, max_turnover_fraction, max_turnover_fraction / 250.0)
y_labels = np.arange(1, max_yes_odds, 0.2)
for max_yes_odds in y_labels:
for max_turnover_fraction in x_labels:
cpmm = run_market(initial_liquidity, fee_fraction, max_turnover_fraction, max_yes_odds, max_slippage, fee_to_liquidity_fraction)
profit = cpmm.fee_pool - cpmm.calc_impermanent_loss()
total_stake = cpmm.lp_token - cpmm.liquidity
yes_odds = cpmm.calc_british_odds(cpmm.calc_buy(1, initial_liquidity * max_slippage)[0], initial_liquidity * max_slippage)
profit_mx.append([total_stake, yes_odds, profit])
return profit_mx
def display_scatter(initial_liquidity, fee_fraction, max_slippage, fee_to_liquidity_fraction, profit_mx):
df = pd.DataFrame(data=profit_mx, columns=["total stake", "odds", "profit"])
color_continuous_scale = ["red", "white", "green"]
fig = px.scatter(df,
title=f"Profit/Loss: {initial_liquidity} liquidity at 1:1, {fee_fraction*100}% fee with {fee_to_liquidity_fraction*100}% reinvested {max_slippage*100}% max slippage",
labels=dict(x="Stake as multiple of initial liquidity", y="Odds divergence from 1:1", color="Profit/Loss as % of initial"),
color_continuous_midpoint=0,
color_continuous_scale=color_continuous_scale,
x=df["total stake"] / initial_liquidity,
y="odds",
color=df["profit"]*100/initial_liquidity)
fig.update_yaxes(ticksuffix=":1")
display(fig)
# profit_mx = run_scatter(10000, 0.02, 50, 8, 0.02)
display_scatter(10000, 0.02, 0.02, 0, profit_mx)
# profit_mx_2 = run_scatter(1000000, 0.02, 50, 8, 0.02)
display_scatter(1000000, 0.02, 0.02, 0, profit_mx_2)
# profit_mx_3 = run_scatter(10000, 0.02, 200, 8, 0.08)
display_scatter(10000, 0.02, 0.08, 0, profit_mx_3)
# profit_mx_4 = run_scatter(10000, 0.02, 50, 8, 0.02, 0.5)
display_scatter(10000, 0.02, 0.02, 0.5, profit_mx_4)